#!coding:utf-8
# vim: tabstop=4 shiftwidth=4 softtabstop=4
import base64
from django.db import transaction
from django.db.models import Count
from rest_framework import mixins, status
from cvirt.manager.serializers import ClusterSerializer, HostSerializer,\
    VMSerializer, StorageSerializer, NetworkSerializer, TemplateSerializer,VM_no_relation_serializer,vdiskSerializer
from cvirt.manager.models import Datacenter, Network, Template
from cvirt.manager.views import BaseListAPIView, BaseRetriveAPIView, NamedAPIViewMixIn
from rest_framework.response import Response
from cvirt.manager.models import Server,Cluster, Instance, Storage,VDisk
from cvirt.tasks import delete_disk
from django.db.models import Q, Sum
from cvirt.common import config,translate as _
from cvirt.manager.models import IscsiLun

conf = config.load_settings()

class ClusterList(NamedAPIViewMixIn,BaseListAPIView):
    model = Cluster
    serializer_class = ClusterSerializer

    def _get(self, request, *args, **kwargs):
        scope = self.get_query_string('scope')
        if scope == 'notempty':
            clusters = filter(lambda c:c.server_set.count()>0,Cluster.objects.all())
            return Response(self.get_serializer(clusters,many=True).data)
        return self.list(request,*args,**kwargs)

    def create(self, request, *args, **kwargs):
        name = request.DATA.get('name')
        desc = request.DATA.get('description')
        cpufamily = request.DATA.get('cpufamily')
        datacenter = Datacenter.objects.get_or_none(pk=request.DATA.get('datacenter'))
        if name and datacenter:
            if not Cluster.objects.get_or_none(name=name):
                cluster = Cluster.objects.create(name=name,cpufamily=cpufamily,description=desc,datacenter=datacenter)
                return Response(self.get_serializer(cluster).data, status=status.HTTP_201_CREATED)
            else:
                return Response(_('集群%s已存在' % name),status.HTTP_400_BAD_REQUEST)
        return Response(_("名称或者数据中心id不能为空"), status=status.HTTP_400_BAD_REQUEST)

class ClusterInfo(NamedAPIViewMixIn,BaseRetriveAPIView):
    """overview of cluster info"""
    model = Cluster
    serializer_class = ClusterSerializer

    def _get(self,request, *args, **kwargs):
        cluster = Cluster.objects.get_or_none(pk=self.pk)
        response = self.retrieve(request,*args,**kwargs)
        if cluster:
            os_types = Instance.objects.values('os_type').filter(host__cluster=cluster).annotate(count=Count('os_type'))
            os_types = dict([(os['os_type'],os['count']) for os in os_types])
            response.data.update(dict(os_info=os_types))

            storagetotal = Storage.objects.exclude(type='iso').aggregate(storage=Sum('totalsize'))
            usedstorage = Storage.objects.exclude(type='iso').aggregate(storage=Sum('used'))

            if storagetotal['storage'] and usedstorage['storage']:
                unused = int(storagetotal['storage']) - int(usedstorage['storage'])
                response.data.update(dict(storage_info={'已使用':usedstorage['storage'],'未使用':unused}))

        return response

    def delete(self, request, *args, **kwargs):
        if Server.objects.filter(cluster_id=self.pk).count()>0:
            return Response(_('只有空集群才允许删除'),status.HTTP_400_BAD_REQUEST)
        return self.destroy(request, *args, **kwargs)


    def hosts(self, request, *args, **kwargs):
        qset = Server.objects.filter(cluster__id=self.pk)
        data = self.paginate(request,qset,HostSerializer)
        for server in data.get('data'):
            server['password'] = base64.b64encode(server.get('password'))
            server['username'] = base64.b64encode("root")
        return Response(data)

    def networks(self, request, *args, **kwargs):
        qset = Network.objects.filter(cluster__id=self.pk)
        data = self.paginate(request,qset,NetworkSerializer)
        return Response(data)

    def vms(self, request, *args, **kwargs):
        qset = Instance.objects.filter(host__cluster__id=self.pk)
        data = self.paginate(request,qset,VMSerializer)
        return Response(data)

    def storages(self, request, *args, **kwargs):
        alive = request.GET.get('alive',False)
        params = dict(cluster__id=self.pk)
        if alive == 'true':
            params.update({'status':'running'})
        qset = Storage.objects.filter(**params).order_by('-type')
        data = self.paginate(request,qset,StorageSerializer)
        return Response(data)

    def templates(self, request, *args, **kwargs):
        status = self.get_params('status')
        params = dict(storage__cluster__id=self.pk)
        if status:
            params['status'] = status

        qset = Template.objects.filter(**params)
        data = self.paginate(request,qset,TemplateSerializer)
        return Response(data)

    """数据中心负载前5主机"""
    def top_hosts(self,request,*args,**kwargs):
        num = self.get_query_string('n')
        num = num if num else 5
        servers = Server.objects.filter(cluster__id=self.pk,status=2).order_by('cpu_usage','mem_usage')[:num]
        return Response(HostSerializer(servers,many=True).data)

    def top_vms(self,request,*args,**kwargs):
        num = self.get_query_string('n')
        num = num if num else 5
        insts = Instance.objects.filter(host__cluster__id=self.pk,status='running').order_by('cpu_usage','mem_usage')[:num]
        return Response(VM_no_relation_serializer(insts,many=True).data)

    def vdisks(self,request,*args,**kwargs):
        qset = VDisk.objects.filter(storage__cluster__id=self.pk,device_type='disk')
        data = self.paginate(request,qset,vdiskSerializer)
        return Response(data)

    def delete_disk(self,request,*args,**kwargs):
        '''
        删除集群中游离的磁盘
        @param request:
        @param args:
        @param kwargs:
        @return:
        '''
        disk = VDisk.objects.get_or_none(pk=self.get_params('disk')['id'])
        if disk:
            hosts = delete_disk.alive_hosts(disk.storage.cluster.id)
            if not hosts: return Response('no host is alive',status.HTTP_400_BAD_REQUEST)
            result = delete_disk.async_call(hosts[0],disk,cleanup=True)
            return Response(dict(activity=result.id))

        return Response('instance and disk id can not be null',status.HTTP_400_BAD_REQUEST)


    @transaction.commit_on_success
    def add_dissociate_disk(self,request,*args,**kwargs):
        disk = self.get_params('disk')
        if not disk['size'].isdigit():
            return Response(_("磁盘大小必须是数字"),status.HTTP_400_BAD_REQUEST)
        storage = Storage.objects.get_or_none(pk=disk['storage']['id'])
        if storage:
            if (storage.free() - int(disk['size'])) < conf.get_int('disk.reserve') and storage.protocol != 'iscsi':
                return Response(_('存储剩余空间%s不足以创建大小为%s的磁盘' % (storage.free(), disk['size'])),
                                status.HTTP_400_BAD_REQUEST)
            if storage.protocol=='iscsi':
                lun = disk['lun']
                if IscsiLun.objects.first(target=storage.target, path=lun['path']):
                    return Response(_("lun虚拟磁盘已存在"),status.HTTP_400_BAD_REQUEST)
                #disk dev和instance为空
                vdisk = VDisk.objects.create(name=disk['name'],format=disk['format'],device_type=disk['device_type'],
                                             size=disk['size'],
                                             storage=storage,bus=disk['bus'])
                IscsiLun.objects.create(target=storage.target, path=lun['path'], vdisk=vdisk, lun=lun['lunid'])
            else:
                #disk dev和instance为空
                vdisk = VDisk.objects.create(name=disk['name'],format=disk['format'],device_type=disk['device_type'],
                                             size=disk['size'],
                                             storage=storage,bus=disk['bus'])

            return Response(vdiskSerializer(vdisk).data)
        else:
            return Response('storage can not be null',status.HTTP_400_BAD_REQUEST)

    @transaction.commit_on_success
    def update_dissociate_disk(self,request,*args,**kwargs):
        '''
        更新游离磁盘只需要更新数据库，在关联操作中会执行后台逻辑
        @param request:
        @param args:
        @param kwargs:
        @return:
        '''
        disk = self.get_params('disk')
        vdisk = VDisk.objects.get_or_none(pk=disk['id'])
        if vdisk:
            #size有变化才检查磁盘空间
            if vdisk.size != int(disk['size']) and vdisk.storage.free() - int(disk['size']) < conf.get_int('disk.reserve'):
                return Response(_('存储剩余空间%s不足以创建大小为%s的磁盘' % (vdisk.storage.free(), disk['size'])),
                                status.HTTP_400_BAD_REQUEST)
            vdisk.update(dict(size=disk['size'],
                              cache=disk['cache'],iomode=disk['iomode'],bus=disk['bus']))
            return Response(vdiskSerializer(vdisk).data)

        return Response('instance and disk can not be null',status.HTTP_400_BAD_REQUEST)
